/* ==================================================================   
 * Created [2009-4-27 下午11:32:55] by Jon.King 
 * ==================================================================  
 * TSS 
 * ================================================================== 
 * mailTo:jinpujun@hotmail.com
 * Copyright (c) Jon.King, 2009-2012 
 * ================================================================== 
*/

package com.jinhe.tss.core.cachepool;

import com.jinhe.tss.core.cachepool.container.ContainerFactory;
import com.jinhe.tss.core.cachepool.container.IPoolContainer;
import com.jinhe.tss.core.exception.BusinessException;
import com.jinhe.tss.core.util.BeanUtil;


/**
 * <p> ObjectPool.java </p>
 * 
 * 缓存对象池
 * 
 * @author Jon.King 2006-12-28
 */
public class ObjectPool extends AbstractPool implements ICleaner{
 
    // 对象池属性
    private IPoolContainer free; // 空闲的对象池
    private IPoolContainer using; // 使用中的对象池
 
    private static int cleanerCount = 0;  
    private Cleaner  cleaner;   //清理器
    private InitThread initer;
    
    public ObjectPool(){
        
    }
    
    /**
     * 初始化指定数量的对象放入池中。
     * 本方法将产生一个新的线程来初始化这些对象。
     * 本方法跟release()方法是相对立的。
     * @param num
     */
    public final void init() {
        released = false;
        
        Class<?> collectionType = BeanUtil.createClassByName(getCacheStrategy().getPoolCollectionClass());
        if (!IPoolContainer.class.isAssignableFrom(collectionType))
            throw new BusinessException("指定的池集合类类型非法: " + collectionType.getName()
                    + " (必须实现cachepool.container.IPoolContainer接口)");
        
        ContainerFactory factory = ContainerFactory.getInstance();
        free = free != null? free : factory.create(collectionType.getName(), getCacheStrategy().getCode() + "_free");
        using = using != null? using : factory.create(collectionType.getName(), getCacheStrategy().getCode() + "_using");
        
        addObjectPoolListener(new ObjectPoolListener()); //为缓存池添加一个监听器
        
        startInitThread(getCacheStrategy().getInitNum().intValue());
        initCleaner(); 
        
        log.info("缓存池（" + strategy.getName() + "）初始化成功！");
    }
    
    /**
     * 启动初始化线程
     * @param num
     */
    void startInitThread(int num){
        if (num == 0)
            return;
        int maxSize = getCacheStrategy().getPoolSize().intValue();
        if (num > 0  &&  (maxSize == 0 || num <= maxSize)) {
            shutDownIniter();
            (initer = new InitThread(num)).start();
        } else
            throw new IllegalArgumentException("初始化缓冲池的num参数非法");
    }
    
    /**
     * 创建检查间隔最少为5秒的清除线程。
     * 本方法包级私有
     */
    public void initCleaner(){
        shutDownCleaner();
        if (strategy.getCyclelife().longValue() > 0){
            long cyclelife = strategy.getCyclelife().longValue();
            long iVal = cyclelife == 0 ? 1000*60*60*24 : Math.max(1000*5, cyclelife / 5);
            (cleaner = new Cleaner(this, iVal)).start();
        }
    }

    /**
     * 销毁 cleaner, initer 线程
     */
    private void shutDownCleaner() {
        if (cleaner != null) {
            cleaner.halt();
            try {
                cleaner.join(); //等待线程死亡
            } catch (InterruptedException e) {
                log.error("停止旧的cleaner线程时被中断", e);
            }
            cleaner = null;
        }
    }
    private void shutDownIniter() {
        if (initer != null){
            initer.halt();
            try {
                initer.join(); //等待线程死亡
            } catch (InterruptedException e) {
                log.error("停止initer线程时被中断", e);
            }
            initer = null;
        }
    }

    public final void release(boolean forced) {
        if (released) return;
        released = true;
        shutDownCleaner();
        shutDownIniter();
        
        synchronized (this) {
            int rel = 0, failed = 0;
            // 销毁所有的缓存项（包括尚在使用中的）
            if (forced) {
                for (CacheableKey key : using.getKeys()) {
                    try {
                        destroyObject(free.get(key));
                        rel++;
                    } catch (Exception e) {
                        failed++;
                        log.error("无法释放池中的缓存项目", e);
                    }
                }
                using.clear();
            } else {
                if (using.size() > 0) log.info("等待<使用中的>缓存项 被 check in pool...");
                while (using.size() > 0) {
                    try {
                        wait(); // 等待，当连接被checkIn回来时，监听器会调用pool的notifyAll()通知这里
                    } catch (InterruptedException e) {
                    }
                }
            }
            // 销毁当前所有空闲状态的缓存项
            for (CacheableKey key : free.getKeys()) {
                try {
                    destroyObject(free.get(key));
                    rel++;
                } catch (Exception e) {
                    failed++;
                    log.error("无法释放池中的缓存项目", e);
                }
            }
            free.clear();

            String s = "成功释放 " + rel + " 个缓存项";
            if (failed > 0) {
                s += " (有 " + failed + " 个缓存项释放失败)";
            }
            log.info(s);
            
            firePoolEvent(ObjectPoolEvent.POOL_RELEASED);
            listeners.clear();
        }
    }

    /**
     * 线程执行清除池中过期的对象。
     * 当对象尚在使用中，线程将会等待对象返回。对象返回时将触发线程再次执行清除。
     */
    private final class Cleaner extends Thread {
        private ObjectPool pool;
        private long    interval; // 定期清除缓存池时间间隔
        private boolean stopped;  // 缓存Cleaner是否已经被挂起

        Cleaner(ObjectPool pool, long interval) {
            this.setName("CleanerThread_" + Integer.toString(cleanerCount++)); // 设置线程名称
            this.pool = pool;
            this.interval = interval;
        }

        public void start() {
            stopped = false;
            super.start();
        }

        /**
         * 安全的停止线程的运行，将线程挂起
         */
        public void halt() {
            if (!isHalted()) {
                stopped = true;
                interrupt(); // 必要的时间再将线程唤醒
            }
        }

        /**
         * 返回线程的状态，是否被挂起
         */
        public boolean isHalted() {
            return stopped;
        }

        /**
         * 处理过期的对象
         */
        public void run() {
            while (pool.cleaner == Thread.currentThread() && !stopped) {
                try {
                    if (!stopped) {
                       sleep(interval);
                    }
                    synchronized (pool) {
                        if (!pool.purge()) {
                           pool.wait(); //使本cleaner线程进入等待休眠状态。(线程进入该对象的休息室waitSet) 
                           //当pool池的checkIn或者putIn事件被触发时，唤醒本cleaner线程
                        }
                    }
                } catch (InterruptedException e) {
                    log.debug("运行cleaner线程时出错！", e);
                }
            }
        }
    }

    /**
     * 线程执行初始化池中对象。
     */
    private final class InitThread extends Thread{
        private int num;
        private boolean stopped = false;

        private InitThread(int num){
            this.num = Math.min(getCacheStrategy().getPoolSize().intValue(), Math.max(num, 0)); // Ensure 0 < num < poolSize.
        }
        
        public void halt() { stopped = true; }

        /**
         * 生成指定数量的缓存对象。如果池中已有对象存在且数量小于指定数目，则线程将补足不足的对象数目。
         */
        public void run(){
            while ( getSize() < num ){
                if(stopped){
                    log.debug("初始化线程已经停止！");
                    return;
                }   
                try{
                    Cacheable o = arithmetic.create(getCacheStrategy().getCyclelife());
                    if (o == null){
                        String errorMsg = ObjectPool.this.getName() + "池初始化时无法创建对象";
                        log.error(errorMsg);
                        throw new BusinessException(errorMsg);
                    }else{
                        putObject(o.getKey(), o.getValue());
                    }
                }catch (Exception e){
                    log.error("无法在池中初始化对象", e);
                    stopped = true; //如果本次循环创建对象失败，则将线程标记设置为停用，下次循环判断的时候即可推出循环，以免进入死循环。
                }
            }
            log.debug(ObjectPool.this.getName() + "池中初始化了 " + getSize() + " 个新的对象");
        }
    }
    
    public IPoolContainer getFree() { return free; }

    public IPoolContainer getUsing() { return using; }

    public final synchronized int getSize() { 
        return (free == null ? 0 : free.size()) + (using == null ? 0 : using.size()); 
    }
}
